package com.csproj.siiat.aop.logging;

import com.csproj.siiat.base.common.logback.Logback;
import com.csproj.siiat.base.common.service.SendMailService;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * Aspect for logging execution of service and repository Spring components.
 *
 * By default, it only runs with the "dev" profile.
 */
@Aspect
public class LoggingAspect {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    private final Environment env;
    @Autowired
    private SendMailService sendMailService;

    public LoggingAspect(Environment env){
        this.env = env;
    }

    /**
     * Pointcut that matches all Spring beans in the application's main packages.
     */
    @Pointcut("within(com.csproj.siiat.repository..*)"+
        " || within(com.csproj.siiat.service..*)"+
        " || within(com..csproj.siiat.web.rest..*)")
    public void applicationPackagePointcut() {
        // Method is empty as this is just a Pointcut, the implementations are in the advices.
    }

    /**
     * 切点之前的操作
     *
     * @param joinPoint
     */
    @Before("applicationPackagePointcut()")
    public void doBefore(JoinPoint joinPoint) {
        try {
            // 接收到请求，记录请求内容
            String info = joinPointToMsg(joinPoint);
            Logback.info(info, log);
        } catch (Exception e) {
            Logback.error("操作请求日志(INFO)记录失败[com.qdum.royalty.gateway.aop.webLog.WebRequestLogAspect.doBefore()]", e, log);
        }
    }


//    /**
//     * 对于方法抛出异常后的操作
//     * BaseAppException的 400和200不会打印日志文件
//     * @param exception
//     */
//    @AfterThrowing(pointcut = "applicationPackagePointcut()",throwing = "exception")
//    public void afterThrowing(JoinPoint joinPoint,Exception exception) {
//        try{
//            if(exception instanceof BaseAppException){
//                BaseAppException baseAppException=(BaseAppException) exception;
//                if(baseAppException.getErrorCode() == null
//                    ||baseAppException.getErrorCode().equals(BaseDTO.CODE_PARAM)
//                    ||baseAppException.getErrorCode().equals(BaseDTO.CODE_SUCCESS)
//                    ||baseAppException.getErrorCode().equals(BaseDTO.CODE_NOT_ACCEPT)
//                    ||baseAppException.getErrorCode().equals(BaseDTO.CODE_NOT_ACCEPT_ORDER)){
//                    return;
//                }
//            }else{
//                String msg = joinPointToMsgForHtml(joinPoint);
//                StringWriter stringWriter = new StringWriter();
//                PrintWriter printWriter = new PrintWriter(stringWriter);
//                exception.printStackTrace(printWriter);
//                sendMailService.sendErrorLogMail(msg+"<br />"+stringWriter.toString());
//            }
//
//            String msg = joinPointToMsg(joinPoint);
//            Logback.error( msg, exception, log);
//        }catch(Exception e){
//            Logback.error("操作错误日志（ERROR）记录失败[com.qdum.royalty.gateway.aop.webLog.WebRequestLogAspect.afterThrowing()]", e,log);
//        }
//
//    }

    /**
     * 根据切点获取请求，返回打印信息
     */
    private String joinPointToMsgForHtml(JoinPoint joinPoint) {
        String beanName = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        Object[] paramsArray = joinPoint.getArgs();
        String params = argsArrayToString(paramsArray);

        StringBuffer info=new StringBuffer();
        info.append("<br />ClassName=["+beanName+"."+methodName+"()]");
        info.append("<br />Params=["+params+"]");
        info.append("<br />CurrentDate=["+new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(new Date())+"]");

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if(attributes != null){
            HttpServletRequest request = attributes.getRequest();
            String uri = request.getRequestURI();
            String remoteAddr = getIpAddr(request);
            String method = request.getMethod();
            info.append("<br />Url=["+request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+uri+"("+method+")]");
            info.append("<br />RemoteAddr=["+remoteAddr+"]<br />");
        }
        return info.toString();
    }

    /**
     * 根据切点获取请求，返回打印信息
     */
    private String joinPointToMsg(JoinPoint joinPoint) {
        // 接收到请求，记录请求内容
        String beanName = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        Object[] paramsArray = joinPoint.getArgs();
        String params = argsArrayToString(paramsArray);
        StringBuffer info=new StringBuffer();
        info.append("\nClassName=["+beanName+"."+methodName+"()]");
        info.append("\nParams=["+params+"]");

        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if(attributes != null){
            HttpServletRequest request = attributes.getRequest();
            String uri = request.getRequestURI();
            String remoteAddr = getIpAddr(request);
            String method = request.getMethod();
            info.append("\nUrl=["+request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+uri+"("+method+")]");
            info.append("\nRemoteAddr=["+remoteAddr+"]");
        }
        return info.toString();
    }

    /**
     * 获取登录用户远程主机ip地址
     *
     * @param request
     * @return
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 请求参数拼装
     *
     * @param paramsArray
     * @return
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        for (Object obj : paramsArray) {
            if (obj instanceof String[]) {
                String[] objAtrr = (String[]) obj;
                params += Arrays.toString(objAtrr)+",";
            } else {
                params += String.valueOf(obj);
            }
        }
        return params.trim();
    }
}
